package us.mmapp;

import java.util.ArrayList;
import java.util.HashMap;

import org.json.JSONArray;

import us.mmapp.entities.ObjectEntity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;

/**
 * Class that manages the clusters for a given set of objects. 
 */
public class ClusterManager
{
	//Images used for representing a cluster
	Drawable mClusterImage;
	Drawable mAudioImage;
	Drawable mVideoImage;
	Drawable mPhotoImage;
	
	Context mContextApp;
	
	private MapView mMapView;
	
	ObjectEntity[] objectList;
	HashMap<Long, ObjectEntity> hashObjects;
	
	ClusterItemizedOverlay[] clustersOverlays;
	
	double[] accepted = {4687500, 585937.3, 146484, 73242, 73242, 18310, 4577, 1144, 286, 71.2};
	
	//double[] accepted = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	//Zooms: (1, 3, 5, 7), (8, 9), (10), (11, 12), (13, 14), (15, 16), (17, 18), (19, 20), 21
	public int whichCluster(int zoomLevel)
	{
		if (zoomLevel <= 7)  return 0;
		if (zoomLevel <= 9)  return 1;
		if (zoomLevel <= 10) return 2;
		if (zoomLevel <= 12) return 3;
		if (zoomLevel <= 14) return 4;
		if (zoomLevel <= 16) return 5;
		if (zoomLevel <= 18) return 6;
		if (zoomLevel <= 20) return 7;
		return 8;
	}
	static final int K = 9;
	public int[] ready;
	/**
	 * The Constructor
	 */
	ClusterManager(Context context, ArrayList<ObjectEntity> objectList, MapView mapView)
	{
		 mClusterImage = context.getResources().getDrawable(R.drawable.cluster_ballon);
		 mAudioImage   = context.getResources().getDrawable(R.drawable.audio_ballon);
		 mVideoImage   = context.getResources().getDrawable(R.drawable.video_ballon);
		 mPhotoImage   = context.getResources().getDrawable(R.drawable.photo_ballon);
		 adjustBounds(mClusterImage);
		 adjustBounds(mAudioImage);
		 adjustBounds(mPhotoImage);
		 adjustBounds(mVideoImage);
		 
		 mMapView =  mapView;
		 mContextApp = context;
		 // list of objects to manage
		 this.objectList = new ObjectEntity[objectList.size()];
		 int i = 0;
		 for (ObjectEntity o : objectList)
		 {
			 this.objectList[i] = o;
			 ++i;
		 }
		 clustersOverlays = new ClusterItemizedOverlay[K];
		 ready = new int[K];
	}
	
	public void prepareCluster(int idx)
	{
		
		ClusterItemizedOverlay iz = new ClusterItemizedOverlay(mClusterImage, mMapView.getContext());	
		int[] unclustered = new int[objectList.length];
		int N = objectList.length;
		for (int i = 0; i < N; ++i) unclustered[i] = i;
		while (N > 0)
		{
			// Take first object
			ObjectEntity first = objectList[unclustered[0]];
			ArrayList<Integer> membri = new ArrayList<Integer>();
			membri.add(unclustered[0]);
			
			unclustered[0] = unclustered[N - 1]; --N;
			// clustured togheter all points within some distance
			
			Drawable marker = null;
			switch (first.getType())
			{
				case 0: marker = mPhotoImage; break;
				case 1: marker = mVideoImage; break;
				case 2: marker = mAudioImage; break;
			}
			
			
			// try clustering
			double aX = first.getLatitude(), aY = first.getLongitude();
			double members = 1;
			for (int i = 0; i < N; ++i)
			{
				ObjectEntity second = objectList[unclustered[i]];
				
				if (Math.abs(second.getLatitude() - first.getLatitude()) * 1000000.0 > accepted[idx]) continue;
				if (Math.abs(second.getLongitude() - first.getLongitude()) * 1000000.0 > accepted[idx]) continue;
				// togheter
				membri.add(unclustered[i]);
				if (members == 1) marker = mClusterImage;
				members += 1;
				aX += second.getLatitude(); aY += second.getLongitude();
				unclustered[i] = unclustered[N-1]; N--; i--;
			}
			DecoratedOverlayItem item = null;
			int[] x = new int[membri.size()];
			int cat = 0;
			for (int y : membri)
			{
				x[cat] = y;
				cat++;
			}
			if (members != 1)
			{
				aX /= members; aY /= members;
				GeoPoint point = new GeoPoint((int)(aX * 1000000.0), (int)(aY * 1000000.0));
				item = new DecoratedOverlayItem(point, "Cluster of " + members, "Cluster of different media objects.",  x);
			}
			else
			{
				GeoPoint point = new GeoPoint((int)(first.getLatitude() * 1000000.0), (int)(first.getLongitude() * 1000000.0));
				item = new DecoratedOverlayItem(point, first.getTitle(), first.getDescription(), x);
			}
			item.setMarker(marker);
			iz.addOverlay(item);
		}
		clustersOverlays[idx] = iz;
		// Mark as ready
		updateReady(idx);
	}
	private synchronized void updateReady(int idx)
	{
		ready[idx] = 1;
	}
	/**
	 * Adjust bounds of a given drawable.
	 * 
	 * @param marker the marker
	 */
	private void adjustBounds(Drawable marker)
	{
		marker.setBounds(-marker.getIntrinsicWidth() / 2, -marker.getIntrinsicHeight(),
				marker.getIntrinsicWidth() / 2, 0);
	}
	class DecoratedOverlayItem extends OverlayItem
	{
		public int[] members;
		private JSONArray jArray;
		public DecoratedOverlayItem(GeoPoint point, String title, String snippet, int[] members)
		{
			super(point, title, snippet);
			this.members = members;
		}
		public JSONArray getJSON()
		{
			return jArray;
		}
		public void computeJSON()
		{
			  jArray = new JSONArray();
			  for (int idx : members)
			  {
				  jArray.put(objectList[idx].toJSON());
			  }
		}
	}
	class ClusterItemizedOverlay extends ItemizedOverlay<DecoratedOverlayItem> 
	{
		private Context mContext;
		private ArrayList<DecoratedOverlayItem> mOverlays;
		public ClusterItemizedOverlay(Drawable defaultMarker)
		{
			super(defaultMarker);
			mOverlays = new ArrayList<DecoratedOverlayItem>();
		}

		public ClusterItemizedOverlay(Drawable marker, Context context)
		{
			super(marker);
			mContext = context;
			mOverlays = new ArrayList<DecoratedOverlayItem>();
		}
		@Override
		protected DecoratedOverlayItem createItem(int i)
		{
			return mOverlays.get(i);
		}

		@Override
		public int size()
		{
			return mOverlays.size();
		}
		public void addOverlay(DecoratedOverlayItem overlay)
		{
		    mOverlays.add(overlay);
		    populate();
		}
		@Override
		protected boolean onTap(int index) {
		
		  DecoratedOverlayItem item = mOverlays.get(index);
		  /*
		  AlertDialog.Builder dialog = new AlertDialog.Builder(mMapView.getContext());
		  dialog.setTitle(item.getTitle());
		  dialog.setMessage(item.getSnippet());
		  dialog.show();
		  */
		  if (item.members.length != 1)
		  {
			  // it's a cluster
			  Intent galleryIntent = new Intent(mContextApp, ClusterGalleryActivity.class);
			  /*if (item.getJSON() == null)
				  item.computeJSON();
			  galleryIntent.putExtra("JSON", item.getJSON().toString());
			  */
			  OnMapActivity.lastCluster = new ArrayList<ObjectEntity>();
			  for (int idx : item.members)
			  {
				  OnMapActivity.lastCluster.add(objectList[idx]);
			  }
			  mContextApp.startActivity(galleryIntent);
		  }
		  else
		  {
			  // it's an individual
			  Intent intent = new Intent(mContextApp, CommentActivity.class);
			  Bundle bundle=new Bundle();
			  bundle.putInt("keyword", (int) objectList[item.members[0]].getId());
			  intent.putExtras(bundle);
			  mContextApp.startActivity(intent);
		  }
		  
		  //this.onTouchEvent(event, mapView)
		  return true;
		}
	}
}